
#include "SDL.h"

#define GL_API_CALL
#define GL_FRAGMENT_SHADER 0x8B30

typedef unsigned int GLenum;
typedef int GLint;
typedef int GLsizei;
typedef unsigned int GLuint;
typedef char GLchar;
typedef float GLfloat;

typedef GLuint (GL_API_CALL *glCreateShaderProgramv_fn) (GLenum type, GLsizei count, const GLchar **strings);
typedef void (GL_API_CALL *glUseProgram_fn) (GLuint program);
typedef void (GL_API_CALL *glTexCoord1f_fn) (GLfloat s);
typedef void (GL_API_CALL *glRecti_fn) (GLint x1, GLint y1, GLint x2, GLint y2);

const GLchar *g_src_fs =
    "float t;"
    "void main(){"
        "t=gl_TexCoord[0].s*.001;"
        "gl_FragColor=vec4(.5+.5*sin(t));"
    "}";

glCreateShaderProgramv_fn glCreateShaderProgramv;
glUseProgram_fn glUseProgram;
glTexCoord1f_fn glTexCoord1f;
glRecti_fn glRecti;

void audio_callback(void *userdata, Uint8 *stream, int len) {
    static int sample = 0;
    static float freq = 440.0f*pow(2.0f,-21/12.0f);
    static int n = 0;

    for (int i = 0; i < len / 2; ++i) {
        const float t = sample++/44100.0f;
        const float w = 2.0f*3.1415926f*freq;

        float y = 0.6f*sin(1.0f*w*t)*exp(-0.0008f*w*t);
        y += 0.3f*sin(2.0f*w*t)*exp(-0.0010f*w*t);
        y += 0.1f*sin(4.0f*w*t)*exp(-0.0015f*w*t);
        y += 0.2f*y*y*y;
        y *= 0.9f + 0.1*cos(70.0f*t);
        y = 2.0f*y*exp(-22.0f*t) + y;

        if (y < -1.0f) y = -1.0f;
        else if (y > 1.0f) y = 1.0f;
        ((short *)stream)[i] = (short)(y*32767.0f);

        if (sample > 5*44100) {
            sample = 0;
            freq = 440.0f*pow(2.0f, (++n-21)/12.0f);
        }
    }
}

int main() {
    SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER);
    SDL_WindowID win = SDL_CreateWindow("test2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
    SDL_GL_CreateContext(win);

    glCreateShaderProgramv = reinterpret_cast<glCreateShaderProgramv_fn>(SDL_GL_GetProcAddress("glCreateShaderProgramv"));
    glUseProgram = reinterpret_cast<glUseProgram_fn>(SDL_GL_GetProcAddress("glUseProgram"));
    glTexCoord1f = reinterpret_cast<glTexCoord1f_fn>(SDL_GL_GetProcAddress("glTexCoord1f"));
    glRecti = reinterpret_cast<glRecti_fn>(SDL_GL_GetProcAddress("glRecti"));

    glUseProgram(glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &g_src_fs));

    SDL_AudioSpec audio_spec = { 44100, AUDIO_S16, 1, 0, 2048, 0, 0, audio_callback, NULL };
    SDL_OpenAudio(&audio_spec, NULL);
    SDL_PauseAudio(0);

    bool run = true;
    while (run) {
        glTexCoord1f((float) SDL_GetTicks());
        glRecti(-1, -1, 1, 1);
        SDL_GL_SwapWindow(win);

        SDL_Event evt;
        while (SDL_PollEvent(&evt)) {
            if (evt.type == SDL_KEYDOWN || evt.type == SDL_QUIT) {
                run = false;
            }
        }
        SDL_Delay(10);
    }

    SDL_CloseAudio();
    SDL_Quit();

    return 0;
}
